/*
 *  KC Bomberman
 *  Copyright 2008 Christian Lins <christian.lins@web.de>
 *  Copyright 2008 Kai Ritterbusch <kai.ritterbusch@googlemail.com>
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package bomberman.client.gui;

import bomberman.client.ClientThread;
import bomberman.server.Playground;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.rmi.RemoteException;
import javax.swing.JPanel;

/**
 * Panel that displays a game's playground. The client
 * receives changes from the server and displays this changes
 * on a PlaygroundPanel.
 * @author Kai Ritterbusch (kai.ritterbusch@fh-osnabrueck.de)
 * @author Christian Lins (christian.lins@web.de)
 */
public class PlaygroundPanel 
        extends JPanel
        implements KeyListener
{
  private ElementPainter[][] elementPainter;
  private boolean spectatorStatus = false;
  
  public PlaygroundPanel(int cols, int rows, boolean spectatorStatus)
  {
    setBackground(Color.BLACK);
    this.spectatorStatus = spectatorStatus;
    GridBagConstraints gbc = new GridBagConstraints();
    GridBagLayout gbl = new GridBagLayout(); 
    setLayout(gbl);
    gbc.fill = GridBagConstraints.BOTH;    

    gbc.gridwidth   = 1;
    gbc.gridheight  = 1;
    gbc.gridx = 0;
    gbc.gridy = 0;
    gbc.insets = new Insets(1, 1, 1, 1);
    
    this.elementPainter = new ElementPainter[cols][rows]; 
    gbl.setConstraints(this, gbc);
    
    for(int y = 0; y < rows; y++)
    {
      gbc.gridy = y;
      for(int x = 0; x < cols; x++)
      {
        gbc.gridx = x;
        this.elementPainter[x][y] = new ElementPainter();
        add(this.elementPainter[x][y], gbc);        
      } 
    }    
    
    MainFrame.getInstance().setSize(
        (cols + 2) * ElementPainter.DEFAULT_SIZE,
        (rows + 2) * ElementPainter.DEFAULT_SIZE);
    
    MainFrame.getInstance().repaint();
  }
  
  /**
   * Draws the die animation
   * @param x
   * @param y
   * @param playerNumber
   */
  public void drawDieAnimation(int x, int y, int playerNumber)
  {
    int explPeriod = 150;
    this.elementPainter[x][y].newDieAnimation(0, explPeriod, playerNumber);
  }
  
  /**
   * Draws explosion animation
   * @param x
   * @param y
   * @param distance
   */
  public void drawExplosion(int x, int y, int distance)
  {   
    int explPeriod = 150;
    this.elementPainter[x][y].newExplosion(0, explPeriod);
    
    boolean skipxp = false;
    boolean skipxm = false;
    boolean skipyp = false;
    boolean skipym = false;
    
    for(int i = 1; i <= distance; i++)
    {
      if(x + i < this.elementPainter.length && !skipxp)
      {
        this.elementPainter[x + i][y].newExplosion(i * explPeriod, explPeriod);
        if(this.elementPainter[x + i][y].getElement() != null)
          skipxp = true;
      }
      if(x - i >= 0 && !skipxm)
      {
        this.elementPainter[x - i][y].newExplosion(i * explPeriod, explPeriod);
        if(this.elementPainter[x - i][y].getElement() != null)
          skipxm = true;
      }
      if(y + i < this.elementPainter[0].length && !skipyp)
      {
        this.elementPainter[x][y + i].newExplosion(i * explPeriod, explPeriod);
        if(this.elementPainter[x][y+i].getElement() != null)
          skipyp = true;
      }
      if(y - i >= 0 && !skipym)
      {
        this.elementPainter[x][y - i].newExplosion(i * explPeriod, explPeriod);
        if(this.elementPainter[x][y-i].getElement() != null)
          skipym = true;
      }
    }
  }
  
  public void keyTyped(KeyEvent event) {}
  public void keyReleased(KeyEvent event) {}
  
  /**
   * Reacts on player actions.
   * @param event
   */
  public void keyPressed(KeyEvent event)
  {    
    try
    {
      // do nothing if the calling client is a Spectator
      if(spectatorStatus == true)
      {      
        if(event.getKeyCode() == KeyEvent.VK_ESCAPE)        
          ClientThread.ServerListener.playerLeftGame();
        return;
      }
      switch(event.getKeyCode())
      {
        case KeyEvent.VK_UP:
        {
          ClientThread.Server.move(ClientThread.Session, 0, -1);
          break;
        }
        case KeyEvent.VK_DOWN:
        {
          ClientThread.Server.move(ClientThread.Session, 0, +1);
          break;
        }
        case KeyEvent.VK_LEFT:
        {
          ClientThread.Server.move(ClientThread.Session, -1, 0);
          break;
        }
        case KeyEvent.VK_RIGHT:
        {
          ClientThread.Server.move(ClientThread.Session, +1, 0);
          break;
        }
        case KeyEvent.VK_SPACE:
        {
          ClientThread.Server.placeBomb(ClientThread.Session);
          break;
        }
        case KeyEvent.VK_ESCAPE:
        {
          ClientThread.Server.leaveGame(ClientThread.Session);          
          ClientThread.ServerListener.playerLeftGame();
          break;
        }
      }
    }
    catch(RemoteException ex)
    {
      ex.printStackTrace();
    }
  }
  
  public void updatePlaygroundView(Playground playground)
  {
    int width  = playground.getWidth();
    int height = playground.getHeight();
    
    for(int x = 0; x < width; x++)
      for(int y = 0; y < height; y++)
       elementPainter[x][y].setElement(playground.getElement(x, y));
    repaint(); 
  }
}
